using Nop.Core;
using Nop.Core.Domain.Orders;
using Nop.Services.Catalog;
using Nop.Services.Orders;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Mvc;
using Spotshub.Api.Models;
using System.Text;
using System.Web;
using Nop.Services.Media;
using Nop.Core.Domain.Discounts;
using Nop.Services.Tax;
using Nop.Core.Log;
using Nop.Core.ApiDataModel;
using Nop.Core.Data;
using Spotshub.Api.Filter;
using Nop.Core.Domain.Customers;
using Nop.Services.Customers;
using ShoppingCartItem = Nop.Core.Domain.Orders.ShoppingCartItem;

namespace Spotshub.Api.Controllers.V1
{
    [ExceptionHandler]
    public class ShoppingCartController : ApiController
    {
        private IWorkContext _workContext;
        private ITaxService _taxService;
        private IProductService _productService;
        private IPictureService _pictureService;
        private IShoppingCartService _shoppingCartService;
        private IOrderTotalCalculationService _orderTotalCalculationService;
        private IRepository<Nop.Core.Domain.Orders.ShoppingCartItem> _sciRepository;
        private readonly ICustomerService _customerService;
        //private ILog _logService;
        public ShoppingCartController(IWorkContext workContext, ITaxService taxService,
            IProductService productService,
            IPictureService pictureService, IShoppingCartService shoppingCartService,
            IOrderTotalCalculationService orderTotalCalculationService,
            IRepository<Nop.Core.Domain.Orders.ShoppingCartItem> sciRepository,
            ICustomerService customerService)
        {
            this._workContext = workContext;
            this._taxService = taxService;
            this._productService = productService;
            this._pictureService = pictureService;
            this._shoppingCartService = shoppingCartService;
            this._orderTotalCalculationService = orderTotalCalculationService;
            this._sciRepository = sciRepository;
            this._customerService = customerService;
            //this._logService = LogManager.GetInstance().GetILog();
        }
        // GET: api/ShoppingCart/get
        public ShoppingCartModel Get()
        {
            var customer = _workContext.CurrentCustomer;
            var shoppingCart = new ShoppingCartModel();
            List<Nop.Core.Domain.Orders.ShoppingCartItem> cart = customer
                .ShoppingCartItems
                .Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart)
                .ToList();

            decimal? tierPrice = null;
            var savedAmount = 0.0m;
            cart.ForEach(shopItem =>
                {
                    if (customer != null && !customer.IsGuest())
                    {
                        tierPrice = GetCustomerTierPrice(shopItem.ProductVariant, customer);
                    }

                    var item = new Nop.Core.ApiDataModel.ShoppingCartItem()
                    {
                        ShoppingCartItemId = shopItem.Id,
                        Quantity = shopItem.Quantity
                    };

                    var product = new Nop.Core.ApiDataModel.Product(_productService.GetProductById(shopItem.ProductVariant.ProductId), shopItem.ProductVariant,
                                new List<string>() { _pictureService.GetPictureUrl(shopItem.ProductVariant.PictureId) });

                    if (tierPrice.HasValue && tierPrice.Value > 0)
                    {
                        product.OldPrice = product.Price;
                        product.Price = tierPrice.Value;
                        product.MemberPrice = tierPrice.Value;
                    }

                    if (product.MemberPrice == product.Price)
                    {
                        savedAmount += (product.OldPrice - product.Price) * item.Quantity;
                    }

                    item.Product = product;
                    shoppingCart.Items.Add(item);
                });

            if (shoppingCart.Items.Count > 0)
            {
                decimal orderSubTotalDiscountAmount2 = decimal.Zero;
                Discount orderSubTotalAppliedDiscount2 = null;
                decimal subTotalWithoutDiscountBase2 = decimal.Zero;
                decimal subTotalWithDiscountBase2 = decimal.Zero;
                _orderTotalCalculationService.GetShoppingCartSubTotal(cart,
                    false, out orderSubTotalDiscountAmount2, out orderSubTotalAppliedDiscount2,
                    out subTotalWithoutDiscountBase2, out subTotalWithDiscountBase2);

                //List<TaxSurcharge> taxRate;
                var taxRate = new List<TaxSurcharge>();
                Discount shippingTotalDiscount = null;
                decimal? orderShippingTotalInclTax = null, orderShippingTotalExclTax = null;
                orderShippingTotalInclTax = _orderTotalCalculationService.GetShoppingCartShippingTotal(cart, true, out taxRate, out shippingTotalDiscount);
                orderShippingTotalExclTax = _orderTotalCalculationService.GetShoppingCartShippingTotal(cart, false);

                decimal? orderTotal = null;
                decimal orderDiscountAmount = decimal.Zero;
                List<AppliedGiftCard> appliedGiftCards = null;
                int redeemedRewardPoints = 0;
                decimal redeemedRewardPointsAmount = decimal.Zero;

                Discount orderAppliedDiscount = null;

                orderTotal = _orderTotalCalculationService.GetShoppingCartTotal(cart,
                    out orderDiscountAmount, out orderAppliedDiscount, out appliedGiftCards,
                    out redeemedRewardPoints, out redeemedRewardPointsAmount, out taxRate);
                var allSurchargeTypes = _taxService.GetAllSurchargeTypes();

                if (taxRate != null && taxRate.Any())
                {
                    shoppingCart.TaxSurcharges = taxRate.Select(tr => new TaxSurchargeModel
                    {
                        SurchargeType = allSurchargeTypes.FirstOrDefault(st => st.Id == tr.SurchargeTypeId).Name,
                        Amount = tr.Value
                    }).ToList();
                }
                shoppingCart.SubTotal = subTotalWithoutDiscountBase2;
                shoppingCart.ShippingFee = orderShippingTotalInclTax.HasValue ? orderShippingTotalInclTax.Value : 0;
                shoppingCart.SavedAmount = orderDiscountAmount + savedAmount;
                shoppingCart.Total = orderTotal.Value;
            }
            return shoppingCart;
        }

        private Nop.Core.Domain.Orders.ShoppingCartItem CheckShoppingCartIsExist(int productVariantId)
        {
            var cart = _workContext.CurrentCustomer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart).ToList();
            var shoppingCartItem = _shoppingCartService.FindShoppingCartItemInTheCart(cart,
                ShoppingCartType.ShoppingCart, this._productService.GetProductVariantById(productVariantId), string.Empty, decimal.Zero);
            return shoppingCartItem;
        }

        private ShoppingCartResultModel UpdateShopCartQuantity(int productVariantId, int quantity)
        {
            var shopcart = CheckShoppingCartIsExist(productVariantId);

            var warnings = new List<string>();
            if (shopcart != null)
            {
                shopcart.Quantity = shopcart.Quantity + quantity;
                warnings.AddRange(_shoppingCartService.GetShoppingCartItemWarnings(_workContext.CurrentCustomer, ShoppingCartType.ShoppingCart,
                    _productService.GetProductVariantById(productVariantId), string.Empty, decimal.Zero, shopcart.Quantity, true));

                var updateSql = "update [ShoppingCartItem] set Quantity=" + shopcart.Quantity + " where Id=" + shopcart.Id;
                if (warnings.Count == 0 && _customerService.ExcuteSql(updateSql, _workContext.CurrentCustomer))
                {
                    return new ShoppingCartResultModel(true, "");
                }
                return new ShoppingCartResultModel(false, string.Join(";", warnings.ToList()));
            }
            return null;
        }

        // POST: api/ShoppingCart/add
        [System.Web.Http.HttpPost]
        public ShoppingCartResultModel Add(int productVariantId, int quantity)
        {
            //var updateQuantity = UpdateShopCartQuantity(productVariantId, quantity);
            //if (updateQuantity != null)
            //{
            //    return updateQuantity;
            //}
            var customer = _customerService.GetCustomerById(_workContext.CurrentCustomer.Id);

            var addToCartWarnings = _shoppingCartService.AddToCart(
                customer,
                this._productService.GetProductVariantById(productVariantId),
                ShoppingCartType.ShoppingCart,
                string.Empty,
                decimal.Zero,
                quantity,
                true);
            if (addToCartWarnings.Count > 0)
            {
                //cannot be added to the cart
                return new ShoppingCartResultModel(false, string.Join(", ", addToCartWarnings.ToList()));
            }
            return new ShoppingCartResultModel(true, "");
        }

        [System.Web.Http.HttpPost]
        public ShoppingCartResultModel Add([FromBody]ShoppingCartVariantModel model)
        {
            //#if DEBUG
            //            string debugMessage = "ProductId:" + model.ProductId + "Quantity:" + model.Quantity + "AttributeIdList:[" + model.AttributeIdList.ToString() + "]AttributeValues:[" + model.AttributeValues.ToString() + "]";
            //            _logService.Debug(debugMessage);
            //#endif

            if (model.AttributeIdList == null && model.AttributeValues == null)
            {


                //var updateQuantity = UpdateShopCartQuantity(model.ProductId, model.Quantity);
                //if (updateQuantity != null)
                //{
                //    return updateQuantity;
                //}

                var customer = _customerService.GetCustomerById(_workContext.CurrentCustomer.Id);

                var addToCartWarnings = _shoppingCartService.AddToCart(
                customer,
                this._productService.GetProductVariantById(model.ProductId),
                ShoppingCartType.ShoppingCart,
                string.Empty,
                decimal.Zero,
                model.Quantity,
                true);
                if (addToCartWarnings.Count > 0)
                {
                    return new ShoppingCartResultModel(false, string.Join(", ", addToCartWarnings.ToList()));
                }
                return new ShoppingCartResultModel(true, "");
            }
            else
            {
                //var updateQuantity = UpdateShopCartQuantity(model.ProductId, model.Quantity);
                //if (updateQuantity != null)
                //{
                //    return updateQuantity;
                //}
                var customer = _customerService.GetCustomerById(_workContext.CurrentCustomer.Id);
                var addToCartWarnings = _shoppingCartService.AddToCart(
                    customer,
                   this._productService.GetProductVariantById(model.ProductId),
                   ShoppingCartType.ShoppingCart,
                   MakeAttributeXml(model),
                   decimal.Zero,
                   model.Quantity,
                   true);
                if (addToCartWarnings.Count > 0)
                {
                    //cannot be added to the cart
                    return new ShoppingCartResultModel(false, string.Join(", ", addToCartWarnings.ToList()));
                }
                return new ShoppingCartResultModel(true, "");
            }
        }

        // POST: api/ShoppingCart/edit/
        [System.Web.Http.HttpPost]
        public ShoppingCartResultModel Edit(int shoppingCartItemId, int quantity)
        {
           var allItems = new List<Nop.Core.Domain.Orders.ShoppingCartItem>();
            Nop.Core.Domain.Orders.ShoppingCartItem shoppingCartItem = _workContext
                .CurrentCustomer
                .ShoppingCartItems
                .Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart && sci.Id == shoppingCartItemId)
                .FirstOrDefault();
            if (shoppingCartItem != null)
            {
                var customer = _customerService.GetCustomerById(_workContext.CurrentCustomer.Id);
                var updateCartWarnings = _shoppingCartService.UpdateShoppingCartItem(
                    customer,
                    shoppingCartItem.Id,
                    quantity,
                    true
                    );
                if (updateCartWarnings.Count > 0)
                {
                    //cannot update the cart                    
                    return new ShoppingCartResultModel(false, string.Join(",", updateCartWarnings.ToList()));
                }

                
                //var productVariant = _productService.GetProductVariantById(shoppingCartItem.ProductVariantId);
                //if (quantity < productVariant.OrderMinimumQuantity)
                //{
                //    var errorMessage=string.Format(_localizationService.GetResource("ShoppingCart.MinimumQuantity"), productVariant.OrderMinimumQuantity));
                //     return new ShoppingCartResultModel(false, errorMessage);
                //}
                //var updateSql = "update [dbo].[ShoppingCartItem] set Quantity='" + quantity + "',UpdatedOnUtc='" + DateTime.UtcNow + "' where Id=" + shoppingCartItemId;
                //var bExcutes = _customerService.ExcuteSql(updateSql, _workContext.CurrentCustomer);
                //if (bExcutes)
                //{
                //    return new ShoppingCartResultModel(true, "");
                //}
                //else
                //{
                //    return new ShoppingCartResultModel(false, "Update Error!");
                //}
            }
            var shoppingCartResultModel = new ShoppingCartResultModel(true, "");
            //shoppingCartResultModel.TaxSurcharges = GetShoppingCartTaxRate(_workContext.CurrentCustomer.ShoppingCartItems.ToList());
            return shoppingCartResultModel;
        }

        [System.Web.Http.HttpPost]
        public ShoppingCartResultModel Edit(ShipCarIdOrQuery ship)
        {
            List<Nop.Core.ApiDataModel.ShoppingCartItem> allItems = new List<Nop.Core.ApiDataModel.ShoppingCartItem>();
            Nop.Core.Domain.Orders.ShoppingCartItem shoppingCartItem = _workContext
                .CurrentCustomer
                .ShoppingCartItems
                .Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart && sci.Id == ship.shoppingCartItemId)
                .FirstOrDefault();
            if (shoppingCartItem != null)
            {
                var updateCartWarnings = _shoppingCartService.UpdateShoppingCartItem(
                    _workContext.CurrentCustomer,
                    shoppingCartItem.Id,
                    ship.quantity,
                    true
                    );
                if (updateCartWarnings.Count > 0)
                {
                    //cannot update the cart                    
                    return new ShoppingCartResultModel(false, string.Join(", ", updateCartWarnings.ToList()));
                }
            }
            var shoppingCartResultModel = new ShoppingCartResultModel(true, "");
            //shoppingCartResultModel.TaxSurcharges = GetShoppingCartTaxRate(_workContext.CurrentCustomer.ShoppingCartItems.ToList());
            return shoppingCartResultModel;
        }

        private List<TaxSurchargeModel> GetShoppingCartTaxRate(IList<ShoppingCartItem> shoppingCartItems)
        {
            var taxList = new List<TaxSurchargeModel>();

            var taxRate = new List<TaxSurcharge>();

            decimal orderDiscountAmount = decimal.Zero;
            List<AppliedGiftCard> appliedGiftCards = null;
            int redeemedRewardPoints = 0;
            decimal redeemedRewardPointsAmount = decimal.Zero;
            Discount orderAppliedDiscount = null;

            _orderTotalCalculationService.GetShoppingCartTotal(shoppingCartItems,
                    out orderDiscountAmount, out orderAppliedDiscount, out appliedGiftCards,
                    out redeemedRewardPoints, out redeemedRewardPointsAmount, out taxRate);

            var allSurchargeTypes = _taxService.GetAllSurchargeTypes();
            if (taxRate != null && taxRate.Any())
            {
                taxList = taxRate.Select(tr => new TaxSurchargeModel
                {
                    SurchargeType = allSurchargeTypes.FirstOrDefault(st => st.Id == tr.SurchargeTypeId).Name,
                    Amount = tr.Value
                }).ToList();
            }
            return taxList;
        }

        // DELETE: api/ShoppingCart/delete
        //[System.Web.Http.HttpPost]
        //public ShoppingCartResultModel Delete(int shoppingCartItemId)
        //{
        //    try
        //    {
        //        //#if DEBUG
        //        //                string debugMessage = "shoppingCartItemId:" + shoppingCartItemId + "CustomerId:" +
        //        //                                      _workContext.CurrentCustomer.Id;
        //        //                _logService.Debug(debugMessage);
        //        //#endif
        //        ShoppingCartItem shopItem = _workContext
        //            .CurrentCustomer
        //            .ShoppingCartItems
        //            .First(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart && sci.Id == shoppingCartItemId);
        //        if (shopItem == null)
        //        {
        //            return new ShoppingCartResultModel(true, "Could not find item in shopping cart.");
        //        }
        //        _shoppingCartService.DeleteShoppingCartItem(shopItem, false);

        //        return new ShoppingCartResultModel(true, "");
        //    }
        //    catch (Exception ex)
        //    {
        //        //_logService.Exception(ex);
        //        return new ShoppingCartResultModel(true, "Delete Error");
        //    }
        //}

        [System.Web.Http.HttpPost]
        public ShoppingCartResultModel Delete(int ShoppingCartItemId)
        {
            Nop.Core.Domain.Orders.ShoppingCartItem shopItem = _workContext
                .CurrentCustomer
                .ShoppingCartItems
                .First(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart && sci.Id == ShoppingCartItemId);
            if (shopItem == null)
            {
                return new ShoppingCartResultModel(true, "Could not find item in shopping cart.");
            }
            //_shoppingCartService.DeleteShoppingCartItem(shopItem, false);
            var deleteSql = "delete from [ShoppingCartItem] where Id=" + ShoppingCartItemId;
            var bExcute = _shoppingCartService.ExcuteSql(deleteSql);
            if (bExcute)
            {
                return new ShoppingCartResultModel(true, "");
            }
            return new ShoppingCartResultModel(false, "Delete Error");
        }

        private string MakeAttributeXml(ShoppingCartVariantModel model)
        {
            var idList = model.AttributeIdList;
            var valueList = model.AttributeValues;

            if (idList == null || idList.Length == 0) return String.Empty;

            if (valueList == null)
            {
                throw new ArgumentException("Values parameter cannot be empty");
            }

            if (idList.Length != valueList.Length)
            {
                throw new ArgumentException("Length of Ids and values are not equal");
            }

            var xmlContent = new StringBuilder("<Attributes>");
            for (int i = 0; i < idList.Length; i++)
            {
                xmlContent.AppendFormat("<ProductVariantAttribute ID=\"{0}\">", idList[i]);
                MakeValueString(xmlContent, valueList[i]);
                xmlContent.Append("</ProductVariantAttribute>");
            }
            xmlContent.Append("</Attributes>");
            return xmlContent.ToString();
        }

        private void MakeValueString(StringBuilder content, string value)
        {
            if (value.IndexOf(',') > 0)
            {
                var values = value.Split(',');
                foreach (var v in values)
                {
                    content.AppendFormat("<ProductVariantAttributeValue><Value>{0}</Value></ProductVariantAttributeValue>", v);
                }
            }
            else
            {
                content.AppendFormat("<ProductVariantAttributeValue><Value>{0}</Value></ProductVariantAttributeValue>", value);
            }
        }

        private static decimal? GetCustomerTierPrice(Nop.Core.Domain.Catalog.ProductVariant productVariant, Customer customer)
        {
            var userRoles = customer.CustomerRoleMappings.Select(m => m.CustomerRole);

            if (productVariant.TierPrices != null)
            {
                var tierPrices = productVariant.TierPrices.Where(tp => tp.CustomerRole.SystemName.Equals(SystemCustomerRoleNames.DreamFactoryUser) && tp.Quantity == 1)
                    .ToList().FilterForCustomer(customer);
                if (tierPrices.Any())
                {
                    var minPrice = tierPrices.Min(tp => tp.Price);
                    if (minPrice < productVariant.Price)
                    {
                        return minPrice;
                    }
                }
            }
            return null;
        }

        private List<string> CheckProductVariantStockQuantity(int productVariantId, int quantity)
        {
            var errorList=new List<string>();
            var shopingCart=CheckShoppingCartIsExist(productVariantId);
            if (shopingCart != null)
            {

            }
            return errorList;
        }
    }
}